#!/usr/local/bin/php * Invision Power Services * IP.Board v3.4.6 * Main public executable wrapper. * Set-up and load module to run * Last Updated: $Date: 2013-02-05 06:22:45 -0500 (Tue, 05 Feb 2013) $ * * * @author $Author: mmecham $ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * * @package IP.Board * * @version $Rev: 11935 $ * */ define( 'IPS_IS_SHELL', TRUE ); define( 'IPB_THIS_SCRIPT', 'public' ); define( 'IPS_CLI_MEMORY_DEBUG', false ); if ( is_file( './initdata.php' ) ) { require_once( './initdata.php' );/*noLibHook*/ } else { require_once( '../initdata.php' );/*noLibHook*/ } require_once( IPS_ROOT_PATH . 'sources/base/ipsRegistry.php' );/*noLibHook*/ require_once( IPS_ROOT_PATH . 'sources/base/ipsController.php' );/*noLibHook*/ $reg = ipsRegistry::instance(); $reg->init(); $moo = new moo( $reg ); class moo { protected $processed = 0; protected $parser; protected $oldparser; protected $start = 0; protected $end = 0; function __construct( ipsRegistry $registry ) { $this->registry = $registry; $this->DB = $this->registry->DB(); $this->settings =& $this->registry->fetchSettings(); $this->request =& $this->registry->fetchRequest(); $this->cache = $this->registry->cache(); $this->caches =& $this->registry->cache()->fetchCaches(); $this->memberData = array(); $this->stdin = fopen('php://stdin', 'r'); //----------------------------------------- // Get new parser and old parser //----------------------------------------- require_once( IPS_ROOT_PATH . "sources/handlers/han_parse_bbcode.php" );/*noLibHook*/ $this->parser = new parseBbcode( $this->registry ); $this->oldparser = new parseBbcode( $this->registry, 'legacy' ); $classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser.php', 'classes_text_parser' ); $this->newParser = new $classToLoad(); //----------------------------------------- // Show options //----------------------------------------- $this->_print( "--------------------------------------------\nWelcome to the IP.Board Post Content Re-Builder\n--------------------------------------------\n" ); $this->_print( "What do you wish to build?\n(c=Calendar Events, a=Announcements, x=Personal Conversations, s=Signatures, m=About me, p=posts, o=Remove Orphaned Posts)\nEnter: " ); $option = $this->_fetchOption(); switch( $option ) { case 'c': $this->_doPosts('cal'); break; case 'a': $this->_doPosts('announce'); break; case 'x': $this->_doPosts('pms'); break; case 's': $this->_doPosts('sigs'); break; case 'm': $this->_doPosts('aboutme'); break; case 'p': $this->_doPosts('posts'); break; case 'o': $this->_doOrphanedPosts(); break; default: $this->_doPosts('posts'); break; } } /** * Rebuild data */ protected function _doOrphanedPosts() { $batch = 250; $c = -1; $bucket = array(); /* Lets grab the highest and lowest IDs */ $rows = $this->DB->buildAndFetch( array( 'select' => "count(pid) AS CNT, max(pid) AS MAX, min(pid) as MIN", 'from' => array( 'posts' => 'p' ), 'where' => 't.tid IS NULL', 'add_join' => array( array( 'select' => 't.*', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=p.topic_id' ) ) ) ); if ( empty( $rows['CNT'] ) ) { $this->_print( "No orphaned posts have been found" ); exit(); } $this->DB->build( array( 'select' => 'pid, from_unixtime(post_date) as time', 'from' => 'posts', 'where' => 'pid IN( ' . $rows['MIN'] . ',' . $rows['MAX'] . ')' ) ); $this->DB->execute(); while( $r = $this->DB->fetch() ) { $posts[ $r['pid'] ] = $r['time']; } $this->_print( "--------------------------------------------\n" . $rows['CNT'] . " orphaned posts found\n--------------------------------------------\n" ); $this->_print( "Oldest: PID:" . $rows['MIN'] . " - Date: " . $posts[ $rows['MIN'] ] ); $this->_print( "Newest: PID:" . $rows['MAX'] . " - Date: " . $posts[ $rows['MAX'] ] ); $this->_print( "Continue? (y/n):" ); $option = $this->_fetchOption(); if ( $option != 'y' ) { $this->_print("Nothing deleted"); exit(); } $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'forums' ) . '/sources/classes/moderate.php', 'moderatorLibrary', 'forums' ); $this->modLibrary = new $classToLoad( $this->registry ); /* Still here? */ $this->DB->build( array( 'select' => "pid", 'from' => array( 'posts' => 'p' ), 'where' => 't.tid IS NULL', 'add_join' => array( array( 'select' => 't.*', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=p.topic_id' ) ) ) ); $o = $this->DB->execute(); while( $post = $this->DB->fetch( $o ) ) { $c++; $bucket[] = $post['pid']; if ( $c % $batch ) { $this->modLibrary->postDeleteFromDb( $bucket, true, true ); $this->_print( $c . ' deleted' ); //$this->_print( var_export( $bucket, true ) ); $bucket = array(); $c = 0; } } $this->_print( "All done" ); } /** * Rebuild data */ protected function _doPosts( $type ) { //----------------------------------------- // Set up //----------------------------------------- $last = 0; $output = array(); $types = array( 'posts', 'pms', 'cal', 'announce', 'sigs', 'aboutme' ); $type = in_array( $type, $types ) ? $type : 'posts'; $groupCache = $this->caches['group_cache']; $this->_print( "Start at ID (Enter 0 to start from the very first entry)\nEnter: " ); $this->start = intval( $this->_fetchOption() ); $this->_print( "Process X rows (Enter 0 to process all rows)\nEnter: " ); $this->end = intval( $this->_fetchOption() ); //----------------------------------------- // Process batches... //----------------------------------------- while( ( $result = $this->_process( $type ) ) !== FALSE ) { $this->_print( $result ); } /* We're done.. */ $this->_print( "COMPLETE" ); /* Update isRebuilt cache */ $sections = array(); $alreadyRebuilt = $this->DB->buildAndFetch( array( 'select' => 'cs_value', 'from' => 'cache_store', 'where' => "cs_key='isRebuilt'" ) ); if( $alreadyRebuilt['cs_value'] ) { $sections = explode( ',', $alreadyRebuilt['cs_value'] ); } $sections[] = $type; $this->DB->replace( 'cache_store', array( 'cs_key' => 'isRebuilt', 'cs_value' => implode( ',', $sections ) ), array( "cs_key" ) ); /* Drop cache */ if ( $type == 'posts' ) { $this->DB->delete( 'content_cache_posts' ); } else if ( $type == 'sigs' ) { $this->DB->delete( 'content_cache_sigs' ); } } /** * Actually process * */ protected function _process( $type ) { if ( $this->end == 0 OR ( $this->end > $this->processed ) ) { /* More to do... */ $batch = 250; $_s = intval( $this->start ); $done = 0; $this->processed += $batch; /* On mssql, the select query blocks all the updates. Doing this causes the engine not to lock */ if ( method_exists( $this->DB, 'setQueryRowLocking' ) ) { $this->DB->setQueryRowLocking( 'OFF' ); } switch( $type ) { case 'cal': $this->DB->build( array( 'select' => 'e.*', 'from' => array( 'cal_events' => 'e' ), 'order' => 'e.event_id ASC', 'where' => 'e.event_id > ' . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=e.event_member_id" ) ) ) ); break; case 'announce': $this->DB->build( array( 'select' => 'a.*', 'from' => array( 'announcements' => 'a' ), 'order' => 'a.announce_id ASC', 'where' => 'a.announce_id > ' . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=a.announce_member_id" ) ) ) ); break; case 'pms': $this->DB->build( array( 'select' => 'p.*', 'from' => array( 'message_posts' => 'p' ), 'order' => 'p.msg_id ASC', 'where' => 'p.msg_id > ' . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=p.msg_author_id" ) ) ) ); break; case 'sigs': $this->DB->build( array( 'select' => 'me.signature, me.pp_member_id', 'from' => array( 'profile_portal' => 'me' ), 'order' => 'me.pp_member_id ASC', 'where' => "me.signature IS NOT NULL AND me.signature != '' AND me.pp_member_id > " . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others, m.members_display_name', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=me.pp_member_id" ) ) ) ); break; case 'aboutme': $this->DB->build( array( 'select' => 'pp.pp_about_me, pp.pp_member_id', 'from' => array( 'profile_portal' => 'pp' ), 'order' => 'pp.pp_member_id ASC', 'where' => "pp.pp_about_me != '' AND pp.pp_about_me IS NOT NULL AND pp.pp_member_id > " . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others, m.members_display_name', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=pp.pp_member_id" ) ) ) ); break; case 'posts': $this->DB->build( array( 'select' => 'p.*', 'from' => array( 'posts' => 'p' ), 'order' => 'p.pid ASC', 'where' => 'p.pid > ' . $_s, 'limit' => array( $batch ), 'add_join' => array( 1 => array( 'type' => 'left', 'select' => 't.forum_id', 'from' => array( 'topics' => 't' ), 'where' => "t.tid=p.topic_id" ), 2 => array( 'type' => 'left', 'select' => 'm.member_group_id, m.mgroup_others', 'from' => array( 'members' => 'm' ), 'where' => "m.member_id=p.author_id" ), 3 => array( 'type' => 'left', 'select' => 'f.*', 'from' => array( 'forums' => 'f' ), 'where' => "t.forum_id=f.id" ) ) ) ); break; } $outer = $this->DB->execute(); //----------------------------------------- // Process... //----------------------------------------- while( $r = $this->DB->fetch( $outer ) ) { //----------------------------------------- // Reset //----------------------------------------- $this->parser->quote_open = $this->oldparser->quote_open = 0; $this->parser->quote_closed = $this->oldparser->quote_closed = 0; $this->parser->quote_error = $this->oldparser->quote_error = 0; $this->parser->error = $this->oldparser->error = ''; $this->parser->image_count = $this->oldparser->image_count = 0; $this->parser->parsing_mgroup = $this->oldparser->parsing_mgroup = $r['member_group_id']; $this->parser->parsing_mgroup_others = $this->oldparser->parsing_mgroup_others = $r['mgroup_others']; /* Clear cached queries */ $this->DB->obj['cached_queries'] = array(); $this->memberData['g_bypass_badwords'] = $this->caches['group_cache'][ $r['member_group_id'] ]['g_bypass_badwords']; switch( $type ) { case 'cal': $this->parser->parse_smilies = $this->oldparser->parse_smilies = $r['event_smilies']; $this->parser->parse_html = $this->oldparser->parse_html = 0; $this->parser->parse_bbcode = $this->oldparser->parse_bbcode = 1; $this->parser->parsing_section = 'calendar'; $rawpost = $this->oldparser->preEditParse( $r['event_content'] ); break; case 'announce': $this->parser->parse_smilies = $this->oldparser->parse_smilies = 1; $this->parser->parse_html = $this->oldparser->parse_html = $r['announce_html_enabled']; $this->parser->parse_bbcode = $this->oldparser->parse_bbcode = 1; $this->parser->parse_nl2br = $this->oldparser->parse_nl2br = $r['announce_nlbr_enabled']; $this->parser->parsing_section = 'announcement'; $rawpost = $this->oldparser->preEditParse( $r['announce_post'] ); break; case 'pms': $this->parser->parse_smilies = $this->oldparser->parse_smilies = 1; $this->parser->parse_html = $this->oldparser->parse_html = $this->caches['group_cache'][ $r['member_group_id'] ]['g_dohtml']; $this->parser->parse_bbcode = $this->oldparser->parse_bbcode = 1; $this->parser->parse_nl2br = $this->oldparser->parse_nl2br = 1; $this->parser->parsing_section = 'pms'; $rawpost = $this->oldparser->preEditParse( $r['msg_post'] ); break; case 'sigs': $this->parser->parse_smilies = $this->oldparser->parse_smilies = 0; $this->parser->parse_html = $this->oldparser->parse_html = $this->caches['group_cache'][ $r['member_group_id'] ]['g_dohtml']; $this->parser->parse_bbcode = $this->oldparser->parse_bbcode = 1; $this->parser->parse_nl2br = $this->oldparser->parse_nl2br = 1; $this->parser->parsing_section = 'signatures'; $rawpost = $this->oldparser->preEditParse( $r['signature'] ); break; case 'aboutme': $this->parser->parse_smilies = $this->oldparser->parse_smilies = 1; $this->parser->parse_html = $this->oldparser->parse_html = $this->caches['group_cache'][ $r['member_group_id'] ]['g_dohtml']; $this->parser->parse_bbcode = $this->oldparser->parse_bbcode = 1; $this->parser->parse_nl2br = $this->oldparser->parse_nl2br = 1; $this->parser->parsing_section = 'aboutme'; $rawpost = $this->oldparser->preEditParse( $r['pp_about_me'] ); break; case 'posts': $allowHtml = ( $r['post_htmlstate'] && $r['use_html'] && $this->caches['group_cache'][ $r['member_group_id'] ]['g_dohtml'] ); $this->newParser->set( array( 'parseArea' => 'topics', 'memberData' => $r, 'parseBBCode' => $r['use_ibc'], 'parseHtml' => $allowHtml, 'parseEmoticons' => $r['use_emo'] ) ); $rawpost = $this->newParser->BBCodeToHtml( $r['post'] ); break; } /* @link http://community.---.com/tracker/issue-36434-rebuild-post-content-remove-break-from-post-content/ New parser retains
, legacy retains \n */ if ( $type == 'posts' || $type == 'sigs' ) { /* Anything special here? */ $newpost = $rawpost; } else { if ( strstr( $rawpost, "\n" ) ) { $rawpost = nl2br( $rawpost ); } $newpost = $this->parser->preDbParse( $rawpost ); } //----------------------------------------- // Remove old \' escaping //----------------------------------------- $newpost = str_replace( "\\'", "'", $newpost ); //----------------------------------------- // Convert old dohtml? //----------------------------------------- $htmlstate = 0; if ( strstr( strtolower($newpost), '[dohtml]' ) ) { //----------------------------------------- // Can we use HTML? //----------------------------------------- if ( $type == 'posts' AND $this->registry->class_forums->forum_by_id[ $r['forum_id'] ]['use_html'] ) { $htmlstate = 2; } $newpost = preg_replace( "#\[dohtml\]#i" , "", $newpost ); $newpost = preg_replace( "#\[/dohtml\]#i", "", $newpost ); } else { $htmlstate = intval( $r['post_htmlstate'] ); } //----------------------------------------- // Convert old attachment tags //----------------------------------------- $newpost = preg_replace( "#\[attachmentid=(\d+?)\]#is", "[attachment=\\1:attachment]", $newpost ); if ( $newpost OR $type == 'sigs' OR $type == 'aboutme' ) { switch( $type ) { case 'posts': $this->DB->update( 'posts', array( 'post' => $newpost, 'post_htmlstate' => $htmlstate ), 'pid='.$r['pid'] ); $string = substr( $r['post'], 0, 30 ) . '...'; $last = $r['pid']; break; case 'pms': $this->DB->update( 'message_posts', array( 'msg_post' => $newpost ), 'msg_id='.$r['msg_id'] ); $string = substr( $r['msg_post'], 0, 30 ) . '...'; $last = $r['msg_id']; break; case 'sigs': $this->DB->update( 'profile_portal', array( 'signature' => $newpost ), 'pp_member_id='.$r['pp_member_id'] ); $string = substr( $r['members_display_name'], 0, 30 ) . '...'; $last = $r['pp_member_id']; break; case 'aboutme': $this->DB->update( 'profile_portal', array( 'pp_about_me' => $newpost ), 'pp_member_id='.$r['pp_member_id'] ); $string = substr( $r['post'], 0, 30 ) . '...'; $last = $r['pp_member_id']; break; case 'cal': $this->DB->update( 'cal_events', array( 'event_content' => $newpost ), 'event_id='.$r['event_id'] ); $string = substr( $r['event_content'], 0, 30 ) . '...'; $last = $r['event_id']; break; case 'announce': $this->DB->update( 'announcements', array( 'announce_post' => $newpost ), 'announce_id='.$r['announce_id'] ); $string = substr( $r['announce_post'], 0, 30 ) . '...'; $last = $r['announce_id']; break; } } unset( $r ); $done++; } if ( method_exists( $this->DB, 'setQueryRowLocking' ) ) { $this->DB->setQueryRowLocking( 'ON' ); } } /* Attempt to free memory */ $this->DB->freeResult( $outer ); /* Memory Debug */ if ( IPS_CLI_MEMORY_DEBUG ) { IPSDebug::setMemoryDebugFlag( "Done", 0 ); foreach( IPSDebug::$memory_debug as $i ) { $this->_print( "Debug:... " . $i[0] . ' - ' . IPSLib::sizeFormat( $i[1] ) ); } /* Reset */ IPSDebug::$memory_debug = array(); } if ( $done ) { $this->start = intval( $last ); return "Completed... " . $this->processed . "(last ID[ " . $last . " ] " . str_replace( "\n", "", $string ) . ")"; } else { return FALSE; } } /** * Out to stdout */ protected function _print( $message, $newline="\n" ) { $stdout = fopen('php://stdout', 'w'); fwrite( $stdout, $message . $newline ); fclose( $stdout ); } /* Fetch option * */ protected function _fetchOption() { return trim( fgets( $this->stdin ) ); } } exit(); ?>